import unittest
import os
import json
from unittest.mock import patch, mock_open
import datetime
import asyncio # 确保导入 asyncio

# 假设 DSLExecutor 在这个路径，需要根据实际路径调整
from backend.DSL.executor.dsl_executor import DSLExecutor 

class TestDSLExecutor(unittest.IsolatedAsyncioTestCase):

    def setUp(self):
        self.workspace_root = "/tmp/test_workspace" # 使用一个临时路径
        self.out_dir = os.path.join(self.workspace_root, "out")
        os.makedirs(self.out_dir, exist_ok=True)
        # DSLExecutor 初始化不再需要 workspace_root
        self.executor = DSLExecutor(out_dir=self.out_dir) 

        self.flow_def = {
            "id": "TEST-FLOW-SEQUENCE",
            "start": "State1",
            "states": {
                "State1": {
                    "action": "match_log_patterns",
                    "pattern": "Pattern1",
                    "file": "app.log",
                    "on_true": "State2",
                    "on_false": "EndFailed"
                },
                "State2": {
                    "action": "match_log_patterns",
                    "pattern": "Pattern2",
                    "file": "app.log",
                    "on_true": "EndSuccess",
                    "on_false": "EndFailed"
                },
                "EndSuccess": {
                    "action": "write_output",
                    "message": "Flow completed successfully"
                },
                "EndFailed": {
                    "action": "write_output",
                    "message": "Flow failed"
                }
            }
        }
        self.base_context = {"log_file": "app.log", "base_log_path": self.workspace_root}
    
    async def test_match_log_patterns_with_timestamp_constraint_success(self):
        log_content = [
            "2023-10-27 10:30:00,123 Pattern1 log entry",
            "2023-10-27 10:30:01,456 Pattern2 log entry"
        ]
        
        # 模拟经过 reboot_analyzer 处理后的日志
        processed_logs = [
            {'datetime': '2023-10-27 10:30:00.123', 'message': 'Pattern1 log entry', 'full_message': '2023-10-27 10:30:00,123 Pattern1 log entry', 'run_stage_id': 0},
            {'datetime': '2023-10-27 10:30:01.456', 'message': 'Pattern2 log entry', 'full_message': '2023-10-27 10:30:01,456 Pattern2 log entry', 'run_stage_id': 0}
        ]

        result = await self.executor.run(self.flow_def, processed_logs, self.base_context)
        self.assertTrue(result["final_state"] == "EndSuccess")
        self.assertEqual(len(result["evidence"]), 2)
        self.assertTrue("last_match_timestamp" in result)
        self.assertEqual(result["last_match_timestamp"], datetime.datetime(2023, 10, 27, 10, 30, 1, 456000).isoformat(timespec='microseconds'))

    async def test_match_log_patterns_with_timestamp_constraint_failure(self):
        log_content = [
            "2023-10-27 10:30:01,456 Pattern1 log entry",
            "2023-10-27 10:30:00,123 Pattern2 log entry (乱序日志，应该被忽略)"
        ]
        
        processed_logs = [
            {'datetime': '2023-10-27 10:30:01.456', 'message': 'Pattern1 log entry', 'full_message': '2023-10-27 10:30:01,456 Pattern1 log entry', 'run_stage_id': 0},
            {'datetime': '2023-10-27 10:30:00.123', 'message': 'Pattern2 log entry (乱序日志，应该被忽略)', 'full_message': '2023-10-27 10:30:00,123 Pattern2 log entry (乱序日志，应该被忽略)', 'run_stage_id': 0}
        ]

        result = await self.executor.run(self.flow_def, processed_logs, self.base_context)
        self.assertTrue(result["final_state"] == "EndFailed")
        self.assertEqual(len(result["evidence"]), 1)
        self.assertTrue("last_match_timestamp" in result)
        self.assertEqual(result["last_match_timestamp"], datetime.datetime(2023, 10, 27, 10, 30, 1, 456000).isoformat(timespec='microseconds'))

    async def test_match_log_patterns_with_no_timestamp_in_log(self):
        log_content = [
            "Pattern1 log entry without timestamp",
            "2023-10-27 10:30:01,456 Pattern2 log entry"
        ]
        
        processed_logs = [
            {'datetime': 'Pattern1 log entry without timestamp', 'message': 'Pattern1 log entry without timestamp', 'full_message': 'Pattern1 log entry without timestamp', 'run_stage_id': 0},
            {'datetime': '2023-10-27 10:30:01.456', 'message': 'Pattern2 log entry', 'full_message': '2023-10-27 10:30:01,456 Pattern2 log entry', 'run_stage_id': 0}
        ]

        result = await self.executor.run(self.flow_def, processed_logs, self.base_context)
        self.assertTrue(result["final_state"] == "EndFailed")
        self.assertEqual(len(result["evidence"]), 0)

    async def test_match_log_patterns_with_different_log_format(self):
        log_content = [
            "2025-07-24 11:30:57.517640 sensor NOTICE: Pattern1 log entry",
            "2025-07-24 11:30:58.000000 sensor NOTICE: Pattern2 log entry"
        ]
        
        processed_logs = [
            {'datetime': '2025-07-24 11:30:57.517640', 'message': 'sensor NOTICE: Pattern1 log entry', 'full_message': '2025-07-24 11:30:57.517640 sensor NOTICE: Pattern1 log entry', 'run_stage_id': 0},
            {'datetime': '2025-07-24 11:30:58.000000', 'message': 'sensor NOTICE: Pattern2 log entry', 'full_message': '2025-07-24 11:30:58.000000 sensor NOTICE: Pattern2 log entry', 'run_stage_id': 0}
        ]

        result = await self.executor.run(self.flow_def, processed_logs, self.base_context)
        self.assertTrue(result["final_state"] == "EndSuccess")
        self.assertEqual(len(result["evidence"]), 2)
        self.assertTrue("last_match_timestamp" in result)
        self.assertEqual(result["last_match_timestamp"], datetime.datetime(2025, 7, 24, 11, 30, 58, 0).isoformat(timespec='microseconds'))

    async def test_run_with_reboot_scenarios_single_reboot(self):
        # 模拟一次重启，run_stage_id 从 0 变为 1
        processed_logs = [
            # 阶段 0
            {'datetime': '2023-10-27 10:00:00.000', 'message': 'Pattern1 for stage 0', 'full_message': '2023-10-27 10:00:00.000 Pattern1 for stage 0', 'run_stage_id': 0},
            {'datetime': '2023-10-27 10:00:01.000', 'message': 'Pattern2 for stage 0', 'full_message': '2023-10-27 10:00:01.000 Pattern2 for stage 0', 'run_stage_id': 0},
            # 重启发生，新的阶段开始
            {'datetime': '2023-10-27 11:00:00.000', 'message': 'Pattern1 for stage 1 (after reboot)', 'full_message': '2023-10-27 11:00:00.000 Pattern1 for stage 1 (after reboot)', 'run_stage_id': 1},
            {'datetime': '2023-10-27 11:00:01.000', 'message': 'Pattern2 for stage 1 (after reboot)', 'full_message': '2023-10-27 11:00:01.000 Pattern2 for stage 1 (after reboot)', 'run_stage_id': 1},
        ]

        result = await self.executor.run(self.flow_def, processed_logs, self.base_context)
        
        # 验证最终结果是否包含所有阶段
        self.assertEqual(len(result['all_run_stage_results']), 2)

        # 验证第一个阶段
        stage0_result = result['all_run_stage_results'][0]
        self.assertEqual(stage0_result['run_stage_id'], 0)
        self.assertEqual(stage0_result['final_state'], 'EndSuccess')
        self.assertEqual(len(stage0_result['evidence']), 2)

        # 验证第二个阶段
        stage1_result = result['all_run_stage_results'][1]
        self.assertEqual(stage1_result['run_stage_id'], 1)
        self.assertEqual(stage1_result['final_state'], 'EndSuccess')
        self.assertEqual(len(stage1_result['evidence']), 2)

    async def test_run_with_reboot_scenarios_multiple_reboot(self):
        # 模拟多次重启
        processed_logs = [
            # 阶段 0
            {'datetime': '2023-10-27 10:00:00.000', 'message': 'Pattern1 stage 0', 'full_message': '2023-10-27 10:00:00.000 Pattern1 stage 0', 'run_stage_id': 0},
            {'datetime': '2023-10-27 10:00:01.000', 'message': 'Pattern2 stage 0', 'full_message': '2023-10-27 10:00:01.000 Pattern2 stage 0', 'run_stage_id': 0},
            # 阶段 1 - 第一次 1970 时间跳变
            {'datetime': '1970-01-01 00:00:01.000', 'message': 'Reboot 1 start (1970)', 'full_message': '1970-01-01 00:00:01.000 Reboot 1 start (1970)', 'run_stage_id': 1},
            {'datetime': '2023-10-27 11:00:00.000', 'message': 'Reboot 1 end (normal time)', 'full_message': '2023-10-27 11:00:00.000 Reboot 1 end (normal time)', 'run_stage_id': 1},
            {'datetime': '2023-10-27 11:00:01.000', 'message': 'Pattern2 stage 1', 'full_message': '2023-10-27 11:00:01.000 Pattern2 stage 1', 'run_stage_id': 1},
            # 阶段 2 - 特定日志触发
            {'datetime': '2023-10-27 12:00:00.000', 'message': '[:00000002] framework: LAUNCH snlua bootstrap (Reboot 2 trigger)', 'full_message': '2023-10-27 12:00:00.000 [:00000002] framework: LAUNCH snlua bootstrap (Reboot 2 trigger)', 'run_stage_id': 2},
            {'datetime': '2023-10-27 12:00:01.000', 'message': 'Pattern2 stage 2', 'full_message': '2023-10-27 12:00:01.000 Pattern2 stage 2', 'run_stage_id': 2},
            # 阶段 3 - 再次 1970 时间跳变
            {'datetime': '1970-01-01 00:00:05.000', 'message': 'Reboot 3 start (1970)', 'full_message': '1970-01-01 00:00:05.000 Reboot 3 start (1970)', 'run_stage_id': 3},
            # 阶段 4 - 1970 内部回跳
            {'datetime': '1970-01-01 00:00:03.000', 'message': 'Reboot 3 internal rollback', 'full_message': '1970-01-01 00:00:03.000 Reboot 3 internal rollback', 'run_stage_id': 4},
            {'datetime': '2023-10-27 13:00:00.000', 'message': 'Reboot 3 end (normal time)', 'full_message': '2023-10-27 13:00:00.000 Reboot 3 end (normal time)', 'run_stage_id': 4},
            {'datetime': '2023-10-27 13:00:01.000', 'message': 'Pattern2 stage 4', 'full_message': '2023-10-27 13:00:01.000 Pattern2 stage 4', 'run_stage_id': 4},
        ]

        result = await self.executor.run(self.flow_def, processed_logs, self.base_context)

        self.assertEqual(len(result['all_run_stage_results']), 5)

        # 阶段 0 (id=0)
        stage0_result = result['all_run_stage_results'][0]
        self.assertEqual(stage0_result['run_stage_id'], 0)
        self.assertEqual(stage0_result['final_state'], 'EndSuccess')
        self.assertEqual(len(stage0_result['evidence']), 2)

        # 阶段 1 (id=1)
        stage1_result = result['all_run_stage_results'][1]
        self.assertEqual(stage1_result['run_stage_id'], 1)
        # 这里 Pattern1 无匹配
        # 但基于当前时间戳顺序与阶段重置逻辑，视为链路不完整，最终为失败。
        # 所以最终会是 EndFailed, evidence = 0
        self.assertEqual(stage1_result['final_state'], 'EndFailed')
        self.assertEqual(len(stage1_result['evidence']), 0)

        # 阶段 2 (id=2)
        stage2_result = result['all_run_stage_results'][2]
        self.assertEqual(stage2_result['run_stage_id'], 2)
        self.assertEqual(stage2_result['final_state'], 'EndFailed')
        self.assertEqual(len(stage2_result['evidence']), 0) # Pattern1 和 Pattern2 都会匹配

        # 阶段 3 (id=3) - Pattern1 乱序
        stage3_result = result['all_run_stage_results'][3]
        self.assertEqual(stage3_result['run_stage_id'], 3)
        self.assertEqual(stage3_result['final_state'], 'EndFailed') # Pattern1 找不到
        self.assertEqual(len(stage3_result['evidence']), 0)

        # 阶段 4 (id=4) - Pattern1 乱序
        stage4_result = result['all_run_stage_results'][4]
        self.assertEqual(stage4_result['run_stage_id'], 4)
        self.assertEqual(stage4_result['final_state'], 'EndFailed') # Pattern1 找不到，但这里模拟的是1970内部回滚，然后跳回正常时间
        # processed_logs for stage 4:
        # {'datetime': '1970-01-01 00:00:03.000', 'message': 'Reboot 3 internal rollback', 'full_message': '1970-01-01 00:00:03.000 Reboot 3 internal rollback', 'run_stage_id': 4},
        # {'datetime': '2023-10-27 13:00:00.000', 'message': 'Reboot 3 end (normal time)', 'full_message': '2023-10-27 13:00:00.000 Reboot 3 end (normal time)', 'run_stage_id': 4},
        # {'datetime': '2023-10-27 13:00:01.000', 'message': 'Pattern2 stage 4', 'full_message': '2023-10-27 13:00:01.000 Pattern2 stage 4', 'run_stage_id': 4},
        # 在 run_stage_id = 4 阶段：
        # - 第一个日志是 1970 的回滚，它会匹配 Pattern1，然后 last_match_timestamp 更新。
        # - 第二个日志是正常时间的 `Reboot 3 end`，它会匹配 Pattern2，然后 last_match_timestamp 更新。
        # - 第三个日志是 `Pattern2 stage 4`，它会再次匹配 Pattern2 (因为时间戳是递增的)，但是不会有新的evidence
        self.assertEqual(len(stage4_result['evidence']), 0) # Pattern1 和 Pattern2 都会匹配 